//------------------------------------------------------------------------------
// Fichiers d'ent�te utilis�s
//------------------------------------------------------------------------------
#include "LinkerOperator.hpp"
#include "Tools/Logger.hpp"
#include <math.h>

//------------------------------------------------------------------------------
// Définition de constantes
//------------------------------------------------------------------------------
#define OUTLINE_MINIMUM_LENGHT 8

namespace ImageAnalysis
{
	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	LinkerOperator::LinkerOperator( Gradiant* gradiant, BinaryImage* refinedImage, OutlineContainer* outlines ):
	Operator(),
	currentRefinedImage(refinedImage),
	currentGradiant(gradiant),
	currentOutlinesContainer(outlines)
	{

	}

	//----------------------------------------------------------------------
	// Destructeur
	//----------------------------------------------------------------------
	LinkerOperator::~LinkerOperator( )
	{

	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void LinkerOperator::Process( )
	{		
		BinaryImage* temporaryImage = new BinaryImage( currentGradiant->GetWidth(), currentGradiant->GetHeight() );

	        // Creation de tous les contours possibles
		int imageSize = currentGradiant->GetWidth()*currentGradiant->GetHeight();
		//unsigned char value = BinaryImage::WHITE_VALUE;
		for( int index = 0; index<imageSize; ++index )
		{
			if( *currentRefinedImage->GetPixel( index ) == BinaryImage::WHITE_VALUE )
			{
				if( *temporaryImage->GetPixel( index ) != BinaryImage::WHITE_VALUE ) // Si le point n'est pas déjà traité
				{
					// Creation du contour
					Outline* outline1 = new Outline();
					RecursiveExploration( index, outline1, currentOutlinesContainer, temporaryImage, true, false );
					//RecursiveExploration( index, outline1, currentOutlinesContainer, temporaryImage, true, true );
					//currentOutlinesContainer->AddOutline( outline1 );	
					Outline* outline2 = new Outline();
					RecursiveExploration( index, outline2, currentOutlinesContainer, temporaryImage, false, true );
					
					
					if( (outline2->GetNumberOfIndex() != 0 ) && ( outline2->GetNumberOfIndex() != 0 ) )
					{	
						// Merge	
						//currentOutlinesContainer->AddOutline( outline1 );
						//currentOutlinesContainer->AddOutline( outline2 );
						
						currentOutlinesContainer->MergeOutline( outline2, outline1, OutlineContainer::START1_START2 );
						//currentOutlinesContainer->MergeOutline( outline2, outline1, true );
						currentOutlinesContainer->AddOutline( outline2 );
						delete outline1;
						//Tools::ILogger::Log("Linker::Dual\n");
					}
					else if( outline1->GetNumberOfIndex() != 0 )
					{
						currentOutlinesContainer->AddOutline( outline1 );
						//Tools::ILogger::Log("Linker::Single(Outline1)\n");
					}
					else if( outline2->GetNumberOfIndex() != 0 )
					{
						currentOutlinesContainer->AddOutline( outline2 );
						//Tools::ILogger::Log("Linker::Single(Outline2)\n");
					}
				}
			}
		}

	}
	
	//----------------------------------------------------------------------
	// Permet de determiner si un ensemble de point appartient au contour
	//----------------------------------------------------------------------
	int LinkerOperator::belongOutline( BinaryImage* temporaryImage, Layer::PixelNeighborHood& neighborHood, Orientation::TOrientation* orientation, bool* belongCandidate  )
	{
		int numberOfCandidate;
		int pixelIndex;

		numberOfCandidate=0;
		for( int orientationIndex=0; orientationIndex<4; ++orientationIndex)
		{
			pixelIndex 			  = neighborHood.index[ orientation[orientationIndex] ];
			belongCandidate[orientationIndex] = (*currentRefinedImage->GetPixel( pixelIndex ) == BinaryImage::WHITE_VALUE) &&
	   			     			    (*temporaryImage->GetPixel( pixelIndex ) != BinaryImage::WHITE_VALUE);
			if( belongCandidate[orientationIndex] )
			{
				//temporaryImage->SetPixel( neighborHood.index[index], &value );
				++numberOfCandidate;
			}
		}		
		return numberOfCandidate;
	}
	
	void LinkerOperator::RecursiveExploration( int currentIndex, Outline* outline, OutlineContainer* container, BinaryImage* temporaryImage, bool direct, bool indirect )
	{
		// Marque que le pixel courant est traite et l'ajout au contour courant
		unsigned char value = BinaryImage::WHITE_VALUE;
		temporaryImage->SetPixel( currentIndex, &value );
		outline->AddIndexAfterEnd( currentIndex );

		// Recuperation du voisinage
		Layer::PixelNeighborHood& neighborHood = currentRefinedImage->GetDirectPixelNeighborHood( currentIndex );
	
		// Test 4 connexites direct
		//   []
		// [][][]
		//   []
		bool possibleCandidate[4];
		int numberOfCandidate;
		Orientation::TOrientation directOrientation[] = { Orientation::NORTH, Orientation::WEST, Orientation::EAST, Orientation::SOUTH };
		numberOfCandidate = belongOutline( temporaryImage, neighborHood, directOrientation, possibleCandidate );
		if( direct && (numberOfCandidate != 0) )
		//--------------------------------------------------------------------------------------
		{
			//ExploreOutline( temporaryImage, numberOfCandidate, neighborHood, directOrientation, belongCandidate, container );
			if( numberOfCandidate == 1 )
			{
				for( int candidateIndex=0; candidateIndex<4; ++candidateIndex )
				{
					// Parcours du nouveau contour si il s'agit du candidat possible
					if( possibleCandidate[candidateIndex] )
					{	RecursiveExploration( neighborHood.index[ directOrientation[candidateIndex]], outline, container, temporaryImage, true, true ); }
				}
			}
			else // donc si numberOfCandidate > 1
			{
				for( int candidateIndex=0; candidateIndex < 4; ++candidateIndex )
				{
					if( possibleCandidate[candidateIndex] )
					{
						// Creation et ajout du nouveau contour
						Outline* newOutline = new Outline();
						container->AddOutline( newOutline );

						// Parcours du nouveau contour
						RecursiveExploration( neighborHood.index[ directOrientation[candidateIndex] ], newOutline, container, temporaryImage, true, true );
					}
				}
			}
		}
		//else//--------------------------------------------------------------------------------------
		if( indirect && (numberOfCandidate == 0) )
		{
			// Test 4 connexites indirect
			// []  []
			//   []
			// []  []
			Orientation::TOrientation indirectOrientation[] = { Orientation::NORTH_WEST, Orientation::NORTH_EAST, Orientation::SOUTH_WEST, Orientation::SOUTH_EAST};
			numberOfCandidate = belongOutline( temporaryImage, neighborHood, indirectOrientation, possibleCandidate );

			if( numberOfCandidate != 0 )
			{
				//ExploreOutline( temporaryImage, numberOfCandidate, neighborHood, indirectOrientation, belongCandidate, container );
				if( numberOfCandidate == 1 )
				{
					for( int candidateIndex=0; candidateIndex < 4; ++candidateIndex )
					{
						// Parcours du nouveau contour si il s'agit du candidat possible
						if( possibleCandidate[candidateIndex] )
						{	RecursiveExploration( neighborHood.index[ indirectOrientation[candidateIndex] ], outline, container, temporaryImage, true, true ); }
					}
				}
				else // donc si numberOfCandidate > 1
				{
					for( int candidateIndex=0; candidateIndex < 4; ++candidateIndex )
					{
						if( possibleCandidate[candidateIndex] )
						{
							// Creation et ajout du nouveau contour
							Outline* newOutline = new Outline();
							container->AddOutline( newOutline );

							// Parcours du nouveau contour
							RecursiveExploration( neighborHood.index[ indirectOrientation[candidateIndex] ], newOutline, container, temporaryImage, true, true );
						}
					}
				}
			}			
		}		
		//--------------------------------------------------------------------------------------		
	}
}

